#ifndef _CAN_UIM_H
#define _CAN_UIM_H

#include "can_app.h"
#include <iostream>
#include <list>
#include "tecan.h"

//sid is a 7 bits data for uim242
//tcw is a 8 bits data for uim242 

#define ACT_SID_P2P(sid) (((sid&0x1f)<<6)+2)
#define ACT_SID_P2G ((0x1f<<6)+3)
#define ACT_EID(sid,tcw) (((sid&0x60)<<8) + tcw)
#define ACT_EID_P2G(tcw) ((0x1f<<13) + tcw)

//#define CAN_ID_UIM(sid,tcw) (ACT_SID(sid)<<18) + ACT_EID(sid,tcw))

//if FG is 1 in the recv frame, it mean the data is not entire, and the following data is coming

typedef struct _uim_data
{
    unsigned char sid;
    unsigned char tcw;    
    unsigned char dlc;
    unsigned char flag;//FG is in the low 4bits, it is P2P or P2G is in the high 4bits.
    unsigned char data[8];
}uim_data;


#define CMD_NEED_ACK(tcw) ((tcw&0x80)?1:0)

int parse_uim_data(void* ptrCanFrame,uim_data* dataOut);

int encap_uim_data(uim_data * data,void* canFrameOut);

void print_uim_data(uim_data * dataToPrint);

void format_cmd(unsigned char ctl_code,unsigned char cmd_code,unsigned char sid,
                unsigned char dlc, unsigned char * data,uim_data *dataOut);


typedef enum
{
    SET_Lamda = 51,
    BTR_Lamda = 53,
    gREG = 64,
    MDL_Lamda = 65,
    ICF = 81,
    MCF = 46,
    FBK = 61,
    ENA = 1,
    OFF = 2,
    ACR = 6,
    MCS = 8,
    CUR = 9,
    MAC = 42,
    MDE = 43,
    MMS = 44,
    MMD = 45,
    SPD = 7,
    STP = 10,
    ORG = 3,
    POS = 11,
    QEC = 12,
    QER = 56,
    SQT = 58,
    BLC = 59,
    SCF = 47,
    SFB = 63,
    STG = 48,
    DOU = 4,
    STO = 54,
    gOFF = 22,
    gORG_Lamda = 23,
    gDOU_Lamda = 24,
    gACR_Lamda = 26,
    gSPD_Lamda = 27,
    gMCS_Lamda = 28,
    gCUR_Lamda = 29,
    gSTP_Lamda = 30,
    gPOS_Lamda = 31,
    gQEC_Lamda = 32,
    IOC = 71,
    DVA = 72,
    PMD = 73,
    PMB = 74,
    PBR = 75,
    AVA = 76,
    OPR = 82,
    DMA = 83,
    ACK_COMMON = 111,
    S1_EDGE = 113,
    NOTIFY_MOVE_END = 117,
    
}EN_CMD_CODE;

typedef enum
{
   NOT_START,
   INITIALIZED,
   MOVING,
   RET_BACKING,
   CHECKING_RET,
   FINISHED,
   ALREADY_ON_ORIGIN, 
   RECV_POS,
   MOVE_END,
   INIT_AWAY_ORIGING,
   INIT_ON_RETBACKPOS,
   INIT_TO_ORIG_1,
   INIT_TO_ON_ORIG_1,
   CHECKING_RET_INIT,
   GETTING_SWITH_STATUS,
}EN_STATUS_MOVE;

typedef enum
{
    RET_BACK_POSITIVE = 0,
    RET_BACK_NEGITIVE = 1,
    NO_RET_BACK = 2,
}en_ret_back;

//typedef enum
//{
//   RET_BACK,
//   MOVE,
//   STOP,
//   QUERY,
//}OPCODE;


int uim_dataProcThreadFunc(void* lparam);

typedef std::list<uim_data> uim_data_list;


#define MAX_LEN_UIM_FRAME 64

//the struct below is for a uim data frame, 
//maybe received in two can frames, and merge into one complete uim frame
typedef struct _uim_frame
{
   unsigned int sid;
   unsigned int len;
   unsigned char isValid;
   unsigned char isComplete;
   unsigned char tcw;
   unsigned char reserved;
   unsigned char data[MAX_LEN_UIM_FRAME];
}uim_frame; 

typedef std::list<uim_frame> uim_frame_list;


typedef struct _uim_dev
{
    int cur_status;
    unsigned int sid;
    uim_frame_list frameList;
}uim_dev;

typedef enum 
{
    OPEN_LOOP,
    CLOSE_LOOP
}en_loop_type;

//mcfg, 1, enable anolog input,
//2,chose s1 for anolog input
//3,if close loop, enable encoder,and closeloop control
//4,enable notification when arrived
//5,enable notification when status in of s1 changed.
#define UIM_MCFG_OPEN 0x8411
#define UIM_MCFG_CLOSE 0xAC11


typedef enum
{
    STOP_WHEN_DOWN,
    STOP_WHEN_UP,
}EN_STOP_EDGE;

#define MAX_UIM_CTL_NUM 38
#define MAX_UIM_CTL_NUM_PCR 16
typedef struct _uim_ctl_desc
{
    unsigned char sid;
    unsigned char ret_dir;//direction when returning back
    unsigned char retFlag;//up edge or down edge when returning back
    unsigned char status;//
    unsigned int max_distance;
    int currPos;
    
    float thetaPerStep;
    float lead;
    unsigned char loopType;
    unsigned char ackFlag;
    void * dataCallBack;
}uim_ctl_desc;

extern uim_ctl_desc * uimCtlArr;
extern uim_ctl_desc * uimCtlArr_pcr;

typedef struct _query_param
{
    unsigned char sid;
    int queryCode;
}query_param;

class CUim_MainCtl:public CCan
{
private:
    std::list<uim_dev> uimDevList;
    CTecan * pTecanInstance;
public:
    int getDevStatus(unsigned int sid);
    void setDevStatus(unsigned int sid, int status);
    int addDev(uim_dev* ptrDev);
    int getDev(unsigned int sidIn,uim_dev& devOut);
    int getDevData(unsigned int sid,uim_frame_list & dataOut);
    int setDevData(unsigned int sid,uim_frame_list & dataIn);
    int addData(uim_frame * dataIn);
    void uim_move(unsigned int sid,int direct,unsigned int position,int loopType);
    void uim_move(void * stMoveParam);

    void uim_move_relative(void * stMoveParam);
    void uim_ret_back(unsigned int sid,int direct,int loopType);
    void uim_ret_back(void * stMoveParam);
    //void uim_stop(move_param * stMoveParam);
    void uim_stop(unsigned int sid);

    void uim_query(query_param * pstQueryParam);
    virtual ~CUim_MainCtl();
    CUim_MainCtl();

    virtual void cmdAct(void * param);//proc the cmd from msg queue.

    virtual int PackagePro( void * frame );

    void findDevsInNet(void);

    void clearData(void);

    int isDevExist(unsigned int sid);

    int initUimDev(unsigned int sid);

    void ack_frame_proc(uim_frame * frameAck);

    int checkMoveParam(void * stMoveParam);
    int checkMoveParam_absolutePos(void * stMoveParam);

    void initTecan(void);

    void setSensorAction(int sid, int isEnable);
    //used when move away origin when init motor
    void setSensorRevert(int sid,int steps);

    void uim_motor_init(int sidIn);

    void uim_motor_init1(int sidIn);

    void uim_motor_retback(void * paramIn, int sidIn);

    void uim_init_last_step(void * stMoveParam);

    void setSensorMoveParam(int sidIn);
};

typedef struct _actThreadParam
{
    unsigned char opcode;
    CUim_MainCtl * pCanInterface;
    void * actParam;
}actThreadParam;

void * uimActThreadFunc(void* lparam);

unsigned char getELeCtlStatus(unsigned char sid);
void setELeCtlStatus(unsigned char sid, unsigned char statusIn);
unsigned char getELeCtlRetdir(unsigned char sid);

unsigned char getELeCtlRetflag(unsigned char sid);

int getELeCtlCurrPos(unsigned char sid);
void setELeCtlCurrPos(unsigned char sid,int curPos);

unsigned int getELeCtlMaxD(unsigned char sid);

unsigned char getELeCtlLoopType(unsigned char sid);

unsigned char getELeCtlAckFlag(unsigned char sid);
void setELeCtlAckFlag(unsigned char sid, unsigned char ackFlagIn);

void setELeCtlBackData(unsigned char sid, void * dataCallBackIn);

void * getELeCtlBackDataPtr(unsigned char sid);


void sendAckToGrpc(int statusCodeIn,int errorNumIn,int sid, int moduleId);

extern int g_msg_id_Q1;

typedef struct _uim_sid_state
{
    int sid;
    int waitTimeMs;
    int waitInterv;
    int currInterv;
    int max_cnt;
}uim_sid_state;


#define STATE_TIMEOUT_MS 20

extern std::list<uim_sid_state> checkingRetList;
extern std::list<uim_sid_state> waitingRetList;

void procUimEleState(void);


void setSensorAction(int sid, int isEnable);


#endif
